home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / smtpserv.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  34KB  |  1,553 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: smtpserv.c 1.13 94/01/04 14:10:28 ROOT_DOS Exp $
  7. *
  8. *    25 Jun 92            paul@wolf.demon.co.uk added automated mail bouncing    
  9. *    13 Jul 92    1.3    GT    Remove 1.2 changes.                            
  10. *  27 Aug 92   1.6    mt@kram.demon.co.uk added smtp separator 
  11. *    03 Sep 92    1.7    GT    Fix missing BOUNCER conditional.            
  12. *    08 Dec 92    1.8    mt@kram.org: Occasional pwait() during copy
  13. *                        cms@home:     Alias-File Mail Bouncing System    
  14. *    19 Mar 93    1.9    GT        Debugging mailit.                            
  15. *    04 Apr 93    1.10    GT        Re-enable beep.                                    
  16. *    05 Apr 93    1.11    GT        Reinstate delay call.                            
  17. *    08 May 93    1.12    GT        Fix warnings.                                    
  18. *                            IAY    Improve behaviour of rest of system                
  19. *                                    while this module is copying files,                
  20. *                                    particularly while in SMTP MODE QUEUE.            
  21. *                            IAY    Fix dot transparency as per RFC 821.            
  22. *                            GBD    Fix alias expansion to allow multiple spaces.
  23. *    08 Dec 93    1.13    GT        Fix bounce message envelope From.                
  24. *                                    Version and compilation date in SMTP banner.    
  25. *                                    Implement VRFY.                                    
  26. *                                    Fix wandering pointer in getmsgtxt ().            
  27. *                                    Close mail spool file before ACK.                
  28. *                                    Fix "." at column 256.                            
  29. *
  30. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  31. *
  32. *    __stdargs smtpserv
  33. *
  34. ****************************************************************************/
  35.  
  36. /*
  37. ** The following definition controls how often the copy_data
  38. ** function calls pwait().  Lower numbers mean better response
  39. ** to other things that may be going on at the expense of the
  40. ** speed of that particular function.
  41. */
  42. #define COPY_DATA_WAIT 1
  43.  
  44. #include <stdio.h>
  45. #include <time.h>
  46.  
  47. #undef    DEBUG_LOCKS
  48.  
  49. #ifdef NOVELL
  50.  
  51. #include "nit.h"
  52. #include <io.h>
  53. #include <dos.h>
  54. #include <dir.h>
  55. #include <time.h>
  56.  
  57. #endif
  58.  
  59. extern    char    novell_server_name[128];
  60. extern    char    novell_mail_ext[4];
  61. extern    unsigned short    novell_start;
  62. extern    char    *smtp_separator;
  63. extern    int        Smtpbeep;
  64.  
  65. #ifdef UNIX
  66. #include <sys/types.h>
  67. #endif
  68. #if    defined(__STDC__) || defined(__TURBOC__)
  69. #include <stdarg.h>
  70. #endif
  71. #include <ctype.h>
  72. #include <setjmp.h>
  73. #include "global.h"
  74. #include "mbuf.h"
  75. #include "cmdparse.h"
  76. #include "socket.h"
  77. #include "iface.h"
  78. #include "proc.h"
  79. #include "smtp.h"
  80. #include "commands.h"
  81. #include "dirutil.h"
  82. #include "bm.h"
  83. #include "mailbox.h"
  84. #include "domain.h"
  85. #include "files.h"
  86. #include "ip.h"
  87.  
  88. char *Days[7] =
  89. {
  90.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  91. }
  92. ;
  93. char *Months[12] =
  94. {
  95.     "Jan","Feb","Mar","Apr","May","Jun",
  96.     "Jul","Aug","Sep","Oct","Nov","Dec"
  97. }
  98. ;
  99.  
  100.  
  101.  
  102. static void copy_data __ARGS((FILE *from, FILE *to));
  103. static struct list *expandalias __ARGS((struct list **head,char *user));
  104. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  105. static struct smtpsv *mail_create __ARGS((void));
  106. static void mail_clean __ARGS((struct smtpsv *mp));
  107. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  108. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  109. static void smtplog __ARGS((char *fmt,...));
  110. static void __stdargs smtpserv __ARGS((int s,void *unused,void *p));
  111. static int mailuser __ARGS((FILE *data,char *from,char *to));
  112. static int validate_user __ARGS((char *user));
  113. static int validate_sender __ARGS((char *sender));
  114. static int remlist __ARGS((struct list **head, struct list *unwanted));
  115.  
  116. /* Command table */
  117. static char *commands[] =
  118. {
  119.     "helo",
  120. #define    HELO_CMD    0
  121.     "noop",
  122. #define    NOOP_CMD    1
  123.     "mail from:",
  124. #define    MAIL_CMD    2
  125.     "quit",
  126. #define    QUIT_CMD    3
  127.     "rcpt to:",
  128. #define    RCPT_CMD    4
  129.     "help",
  130. #define    HELP_CMD    5
  131.     "data",
  132. #define    DATA_CMD    6
  133.     "rset",
  134. #define    RSET_CMD    7
  135.     "expn",
  136. #define EXPN_CMD    8
  137.     "vrfy",
  138. #define VRFY_CMD    9    
  139.     NULLCHAR
  140. }
  141. ;
  142.  
  143. /* Reply messages */
  144. static char Help[]             = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  145. static char Banner[]         = "220 %s %s %s %s SMTP ready\n";
  146. static char Closing[]         = "221 Closing\n";
  147. static char Ok[]                 = "250 Ok\n";
  148. static char Reset[]             = "250 Reset state\n";
  149. static char Sent[]             = "250 Sent\n";
  150. static char Ourname[]         = "250 %s, Pleased to meet you\n";
  151. static char Unwanted[]         = "250 Local policy blocks mail from <%s>\n";
  152. static char Enter[]             = "354 Enter mail, end with .\n";
  153. static char Ioerr[]             = "452 Temp file write error\n";
  154. static char Badcmd[]         = "500 Command unrecognized\n";
  155. static char Lowmem[]         = "421 System overloaded, try again later\n";
  156. static char Syntax[]         = "501 Syntax error\n";
  157. static char Needrcpt[]         = "503 Need RCPT (recipient)\n";
  158. static char Needsender[]    = "503 Local policy blocking mail from you\n";
  159. static char Unknown[]         = "550 <%s> address unknown\n";
  160. static char Noalias[]         = "550 No alias for <%s>\n";
  161. static char UnknownRcpt[]    = "550 Unknown recipient <%s>\n";
  162.  
  163. static failure fail;
  164. static int bad_sender;
  165. char default_address[SLINELEN];
  166.  
  167. static int Ssmtp = -1; /* prototype socket for service */
  168.  
  169. /* Start up SMTP receiver service */
  170. int
  171. smtp1(argc,argv,p)
  172. int argc;
  173. char *argv[];
  174. void *p;
  175. {
  176.     struct sockaddr_in lsocket;
  177.     int s;
  178.  
  179.     if(Ssmtp != -1)
  180.     {
  181.         return 0;
  182.     }
  183.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  184.     chname(Curproc,"SMTP listener");
  185.  
  186.     lsocket.sin_family = AF_INET;
  187.     lsocket.sin_addr.s_addr = INADDR_ANY;
  188.     if(argc < 2)
  189.         lsocket.sin_port = IPPORT_SMTP;
  190.     else
  191.         lsocket.sin_port = atoi(argv[1]);
  192.  
  193.     Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  194.     bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  195.     listen(Ssmtp,1);
  196.     for(;;)
  197.     {
  198.         if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  199.             break;    /* Service is shutting down */
  200.  
  201.         if(availmem() < Memthresh)
  202.         {
  203.             usprintf(s,Lowmem);
  204.             shutdown(s,1);
  205.         }
  206.         else
  207.         {
  208.             /* Spawn a server */
  209.             newproc("SMTP server",2048,smtpserv,s,NULL,NULL,0);
  210.         }
  211.     }
  212.     return 0;
  213. }
  214.  
  215. /* Shutdown SMTP service (existing connections are allowed to finish) */
  216. int
  217. smtp0(argc,argv,p)
  218. int argc;
  219. char *argv[];
  220. void *p;
  221. {
  222.     close_s(Ssmtp);
  223.     Ssmtp = -1;
  224.     return 0;
  225. }
  226.  
  227. static void __stdargs smtpserv(s,unused,p)
  228. int s;
  229. void *unused;
  230. void *p;
  231. {
  232.     struct smtpsv *mp;
  233.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd,*newaddr;
  234.     struct list *ap,*list;
  235.     int cnt;
  236.     char address_type;
  237.  
  238.     sockmode(s,SOCK_ASCII);
  239.     sockowner(s,Curproc);        /* We own it now */
  240.     log(s,"open SMTP");
  241.  
  242.     if((mp = mail_create()) == NULLSMTPSV)
  243.     {
  244.         tprintf(Nospace);
  245.         log(s,"close SMTP - no space");
  246.         close_s(s);
  247.         return;
  248.     }
  249.     mp->s = s;
  250.  
  251.     (void) usprintf(s, Banner, Hostname, Version, __DATE__, __TIME__);
  252.  
  253. loop:
  254.     if ((cnt = recvline(s,buf,sizeof(buf))) == -1)
  255.     {
  256.         /* He closed on us */
  257.         goto quit;
  258.     }
  259.     if(cnt < 4)
  260.     {
  261.         /* Can't be a legal command */
  262.         usprintf(mp->s,Badcmd);
  263.         goto loop;
  264.     }    
  265.     rip(buf);
  266.     cmd = buf;
  267.  
  268.     /* Translate entire buffer to lower case */
  269.     for(cp = cmd;*cp != '\0';cp++)
  270.         *cp = tolower(*cp);
  271.  
  272.     /* Find command in table; if not present, return syntax error */
  273.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  274.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  275.             break;
  276.     if(*cmdp == NULLCHAR)
  277.     {
  278.         (void) usprintf(mp->s,Badcmd);
  279.         goto loop;
  280.     }
  281.     arg = &cmd[strlen(*cmdp)];
  282.     /* Skip spaces after command */
  283.     while(*arg == ' ')
  284.         arg++;
  285.         
  286.     /* Execute specific command */
  287.  
  288.     switch(cmdp-commands) {
  289.     case HELO_CMD:
  290.         free(mp->system);
  291.         mp->system = strdup(arg);
  292.         (void) usprintf(mp->s,Ourname,Hostname);
  293.         break;
  294.     case NOOP_CMD:
  295.         (void) usprintf(mp->s,Ok);
  296.         break;
  297.     case MAIL_CMD:
  298.         bad_sender = 0;
  299.         if((cp = getname(arg)) == NULLCHAR)
  300.         {
  301.             (void) usprintf(mp->s,Syntax);
  302.             break;
  303.         }
  304.         if (!validate_sender(cp))
  305.         {
  306.             (void) usprintf(mp->s,Unwanted,cp);
  307.             smtplog("rejected: from: %s",cp);
  308.             bad_sender = 1;
  309.             break;
  310.         }
  311.         free(mp->from);
  312.         mp->from = strdup(cp);
  313.         (void) usprintf(mp->s,Ok);
  314.         break;
  315.     case QUIT_CMD:
  316.         (void) usprintf(mp->s,Closing);
  317.         goto quit;
  318.     case RCPT_CMD:
  319.         /* Specify recipient */
  320.         fail = NO_FAIL;
  321.         if((cp = getname(arg)) == NULLCHAR)
  322.         {
  323.             (void) usprintf(mp->s,Syntax);
  324.             break;
  325.         }
  326.  
  327.         /* rewrite address if possible */
  328.         if((newaddr = rewrite_address(cp)) != NULLCHAR)
  329.         {
  330.             strcpy(buf,newaddr);
  331.             cp = buf;
  332.             free(newaddr);
  333.         }
  334.  
  335.         /* check if address is ok */
  336.         if ((address_type = validate_address(cp)) == BADADDR)
  337.         {
  338.             (void) usprintf(mp->s,Unknown,cp);
  339.             break;
  340.         }
  341.  
  342.         /* if a local address check for an alias */
  343.         if (address_type == LOCAL)
  344.         {
  345.             expandalias(&mp->to, cp);
  346.             for (ap = mp->to; ap != NULLLIST; ap = ap->next)
  347.             {
  348.                 if (ap->type == LOCAL)
  349.                 {
  350.                     if (!validate_user(ap->val))
  351.                     {
  352.                         switch (fail)
  353.                         {
  354.                         case FAIL_DELIVER:
  355.                             break;
  356.                         case FAIL_DEFAULT:
  357.                             expandalias(&ap->next, default_address);
  358.                             if (validate_user(ap->next->val))
  359.                                 {
  360.                                 remlist(&mp->to, ap);
  361.                                 break;
  362.                                 }
  363.                                 /* else fall through to fail */
  364.                         default:
  365.                             usprintf(mp->s,UnknownRcpt,ap->val);
  366.                             fail = FAIL_BAD;
  367.                             break;
  368.                         }
  369.                     if (fail == FAIL_BAD)
  370.                         break;
  371.                     }
  372.                 }
  373.             }
  374.             if (fail == FAIL_BAD)
  375.                 break;
  376.  
  377.         }
  378.         else
  379.             /* a remote address is added to the list */
  380.             addlist(&mp->to, cp, address_type);
  381.  
  382.         (void) usprintf(mp->s,Ok);
  383.         break;
  384.     case HELP_CMD:
  385.         (void) usprintf(mp->s,Help);
  386.         break;
  387.     case DATA_CMD:
  388.         if ((mp->to == NULLLIST) || fail == FAIL_BAD)
  389.             (void) usprintf(mp->s,Needrcpt);
  390.         else if (bad_sender)
  391.             (void) usprintf(mp->s,Needsender);
  392.         else if ((mp->data = tmpfile()) == NULLFILE)
  393.             (void) usprintf(mp->s,Ioerr);
  394.         else
  395.             getmsgtxt(mp);
  396.         break;
  397.     case RSET_CMD:
  398.         del_list(mp->to);
  399.         mp->to = NULLLIST;
  400.         fail = NO_FAIL;
  401.         (void) usprintf(mp->s,Reset);
  402.         break;
  403.     case EXPN_CMD:
  404.         if (*arg == '\0')
  405.         {
  406.             (void) usprintf(mp->s,Syntax);
  407.             break;
  408.         }
  409.  
  410.         list = NULLLIST;
  411.         /* rewrite address if possible */
  412.         if((newaddr = rewrite_address(arg)) != NULLCHAR)
  413.             if(strcmp(newaddr,arg) == 0)
  414.             {
  415.                 free(newaddr);
  416.                 newaddr = NULLCHAR;
  417.             }
  418.             else
  419.             {
  420.                 strcpy(buf,newaddr);
  421.                 arg = buf;
  422.             }
  423.         list = NULLLIST;
  424.         expandalias(&list,arg);
  425.         if (strcmp(list->val,arg) == 0 && list->next == NULLLIST)
  426.             if(newaddr == NULLCHAR)
  427.             {
  428.                 (void) usprintf(mp->s,Noalias,arg);
  429.                 del_list(list);
  430.                 break;
  431.             }
  432.         ap = list;
  433.         while (ap->next != NULLLIST)
  434.         {
  435.             (void) usprintf(mp->s,"250-%s\n",ap->val);
  436.             ap = ap->next;
  437.         }
  438.         usprintf(mp->s,"250 %s\n",ap->val);
  439.         del_list(list);
  440.         free(newaddr);
  441.         break;
  442.  
  443.     case VRFY_CMD:
  444.         if (*arg == '\0') {
  445.             usprintf(mp->s, Syntax);
  446.             break;
  447.         }
  448.  
  449.         if (validate_user(arg) == 0)
  450.             usprintf(mp->s, UnknownRcpt, arg);
  451.         else
  452.             usprintf(mp->s, Ok);
  453.  
  454.         break;
  455.  
  456.     }
  457.     goto loop;
  458.  
  459. quit:
  460.     log(mp->s,"close SMTP");
  461.     close_s(mp->s);
  462.     mail_clean(mp);
  463.     smtptick(NULL);            /* start SMTP daemon immediately */
  464. }
  465.  
  466. /* read the message text */
  467. static int
  468. getmsgtxt(mp)
  469. struct smtpsv *mp;
  470. {
  471.     char buf[LINELEN];
  472.     register char *p = buf;
  473.     long t;
  474.  
  475.     /* Add timestamp; ptime adds newline */
  476.  
  477.     time(&t);
  478.     fprintf(mp->data,"Received: ");
  479.  
  480.     if (mp->system != NULLCHAR)
  481.         fprintf(mp->data, "from %s ", mp->system);
  482.     fprintf(mp->data, "by %s with SMTP\n\tid AA%ld ; %s",
  483.       Hostname, get_msgid(), ptime(&t));
  484.       
  485.     if (ferror(mp->data)) {
  486.         usprintf(mp->s, Ioerr);
  487.         return 1;
  488.     }
  489.     else
  490.         usprintf(mp->s, Enter);
  491.         
  492.     while(1) {
  493.         int no_check_dot = 0;                    /* don't check for "."                */
  494.         char *has_newline;                        /* nz - line contains newline        */
  495.  
  496.         p = buf;        /* GT 11 Dec 93                        */
  497.  
  498.         if (recvline(mp->s, p, sizeof(buf)) == -1)
  499.             return 1;
  500.  
  501.         has_newline = strchr(p, '\n');
  502.         rip(p);
  503.  
  504.         /*
  505.         ** If the line starts with a '.', this is either
  506.         ** the end of the message or a line where a dot
  507.         ** has been added for "dot transparency"
  508.         */
  509.  
  510.         if (no_check_dot == 0 && *p == '.') {
  511.             /*
  512.             ** Strip off leading '.'; if there is nothing
  513.             ** else on the line, this is the end of the
  514.             ** data.  Otherwise, we have managed to remove
  515.             ** the protecting dot and p now points at the
  516.             ** unprotected message line.
  517.             */
  518.             
  519.             if (*++p == '\0') {
  520.                 int rc;        /* result code                        */
  521.  
  522.                 /* Also sends appropriate response */
  523.  
  524.                  rc = mailit(mp->data, mp->from, mp->to);
  525.                 if (fclose(mp->data) != 0)
  526.                      rc = 1;
  527.  
  528.                  mp->data = NULLFILE;
  529.  
  530.                  if (rc != 0)
  531.                     (void) usprintf(mp->s,Ioerr);
  532.                 else
  533.                     (void) usprintf(mp->s,Sent);
  534.  
  535.                 del_list(mp->to);
  536.                 mp->to = NULLLIST;
  537.                 return 0;
  538.             }
  539.  
  540.         }
  541.  
  542.          if (has_newline != 0)
  543.              no_check_dot = 0;                        /* check "." next time                */
  544.          else
  545.             no_check_dot = 1;                        /* don't check "." next time        */
  546.  
  547.         /* for UNIX mail compatiblity */
  548.  
  549.         if (strncmp(p,"From ",5) == 0)
  550.             (void) putc('>',mp->data);
  551.  
  552.         /* Append to data file */
  553.  
  554.         if(fprintf(mp->data,"%s\n",p) < 0) {
  555.             (void) usprintf(mp->s,Ioerr);
  556.             return 1;
  557.         }
  558.     }
  559. }
  560.  
  561. /* Create control block, initialize */
  562. static struct smtpsv *
  563. mail_create()
  564. {
  565.     register struct smtpsv *mp;
  566.  
  567.     mp = (struct smtpsv *)callocw(1,sizeof(struct smtpsv));
  568.     mp->from = strdup("");    /* Default to null From address */
  569.     return mp;
  570. }
  571.  
  572. /* Free resources, delete control block */
  573. static void
  574. mail_clean(mp)
  575. register struct smtpsv *mp;
  576. {
  577.     if (mp == NULLSMTPSV)
  578.         return;
  579.     free(mp->system);
  580.     free(mp->from);
  581.     if(mp->data != NULLFILE)
  582.         fclose(mp->data);
  583.     del_list(mp->to);
  584.     free((char *)mp);
  585. }
  586.  
  587.  
  588. /* Given a string of the form <user@host>, extract the part inside the
  589.  * brackets and return a pointer to it.
  590.  */
  591. char *
  592. getname(cp)
  593. register char *cp;
  594. {
  595.     register char *cp1;
  596.  
  597.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  598.         return NULLCHAR;
  599.     cp++;    /* cp -> first char of name */
  600.     if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  601.         return NULLCHAR;
  602.     *cp1 = '\0';
  603.     return cp;
  604. }
  605.  
  606. #ifdef NOVELL
  607.  
  608. long int get_mail_id(char *user,char *server)
  609. {
  610.     int        connectionID=1;
  611.     int        cCode=0;
  612.     int        DefCon;
  613.     long    int retval;
  614.     int        err;
  615.  
  616.     cCode=GetConnectionID(server,&connectionID);
  617.  
  618.     DefCon=GetDefaultConnectionID();
  619.  
  620.     if(DefCon!=connectionID)
  621.     {
  622.         SetPreferredConnectionID(connectionID);
  623.     }
  624.  
  625.     cCode=GetBinderyObjectID(user,OT_USER,&retval);
  626.  
  627.     if(cCode!=0)
  628.     {
  629.         retval=0;
  630.     }
  631.  
  632.     if(DefCon!=connectionID)
  633.     {
  634.         SetPrimaryConnectionID(DefCon);
  635.     }
  636.     return    retval;
  637. }
  638.  
  639. void send_alert(char *user,char *server,char *from)
  640. {
  641.     int        numcon,conlist[100],reslist[100];
  642.     int        connectionID=1;
  643.     int        cCode=0;
  644.     int        DefCon;
  645.     long    int retval;
  646.     int        err;
  647.     char    message[128];
  648.  
  649.     cCode=GetConnectionID(server,&connectionID);
  650.  
  651.     DefCon=GetDefaultConnectionID();
  652.  
  653.     if(DefCon!=connectionID)
  654.     {
  655.         SetPreferredConnectionID(connectionID);
  656.     }
  657.  
  658.     cCode=GetObjectConnectionNumbers(user,OT_USER,&numcon,conlist,100);
  659.  
  660.     sprintf(message,"You have mail from %s",from);
  661.  
  662.     message[55]=0; /* Nasty truncation to cope with bindings */
  663.  
  664.     cCode=SendBroadcastMessage(message,conlist,reslist,numcon);
  665.  
  666.     if(DefCon!=connectionID)
  667.     {
  668.         SetPrimaryConnectionID(DefCon);
  669.     }
  670. }
  671.  
  672. #endif
  673.  
  674. /*
  675. ** copy_data
  676. **
  677. ** This function copies all available data from an input file to an
  678. ** output file.  This is done in chunks of LINELEN for efficiency.
  679. ** In addition, the function deschedules itself every so often so
  680. ** that large copy operations of this type do not completely block
  681. ** processing of other operations.
  682. */
  683. static void
  684. copy_data ( from, to )
  685. FILE *from, *to;
  686. {
  687.     int c;
  688.     #if COPY_DATA_WAIT != 1
  689.         int counter = 0;
  690.     #endif
  691.     char buf[LINELEN];
  692.     while ( (c = fread(buf, 1, sizeof(buf), from) ) > 0)
  693.     {
  694.         if (fwrite(buf, 1, c, to) != c)
  695.             break;
  696.         #if COPY_DATA_WAIT == 1
  697.             pwait(NULL);
  698.         #else
  699.             if (++counter == COPY_DATA_WAIT)
  700.             {
  701.                 pwait(NULL);
  702.                 counter = 0;
  703.             }
  704.         #endif
  705.     }
  706. }
  707.  
  708. /* General mailit function. It takes a list of addresses which have already
  709. ** been verified and expanded for aliases. Base on the current mode the message
  710. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  711. */
  712. static int
  713. mailit(data,from,tolist)
  714. FILE *data;
  715. char *from;
  716. struct list *tolist;
  717. {
  718.     struct list *ap, *dlist = NULLLIST;
  719.     register FILE *fp;
  720.     char    mailbox[85], *cp, *host, *qhost;
  721.     int    fail = 0;
  722.     time_t    t;
  723.  
  724.     if ((Smtpmode & QUEUE) != 0)
  725.         return(router_queue(data,from,tolist));
  726.  
  727.     do
  728.     {
  729.         qhost = NULLCHAR;
  730.         for(ap = tolist;ap != NULLLIST;ap = ap->next)
  731.         {
  732. #if    defined (DEBUG_LOCKS)
  733.             smtplog ("mailit (): ap->val = %s", ap->val);
  734.             smtplog ("mailit (): ap->type = %d", ap->type);
  735. #endif
  736.             if (ap->type == DOMAIN)
  737.             {
  738.                 if ((host = strrchr(ap->val,'@')) != NULLCHAR)
  739.                     host++;
  740.                 else
  741.                     host = Hostname;
  742.                 if(qhost == NULLCHAR)
  743.                     qhost = host;
  744.                 if(stricmp(qhost,host) == 0)
  745.                 {
  746.                     ap->type = BADADDR;
  747.                     addlist(&dlist,ap->val,0);
  748.                 }
  749.             }
  750.         }
  751.         if(qhost != NULLCHAR)
  752.         {
  753. #if    defined (DEBUG_LOCKS)
  754.             smtplog ("mailit (): qhost = %s, queueing", qhost);
  755. #endif
  756.             rewind(data);
  757.             queuejob(data,qhost,dlist,from,NULL);
  758.             del_list(dlist);
  759.             dlist = NULLLIST;
  760.         }
  761.     }
  762.     while(qhost != NULLCHAR)
  763.         ;
  764.  
  765.     for(ap = tolist;ap != NULLLIST;ap = ap->next)
  766.     {
  767.         if(ap->type != LOCAL)
  768.         {
  769.             ap->type = DOMAIN;
  770.             continue;
  771.         }
  772.         rewind(data);
  773.         /* strip off host name of LOCAL addresses */
  774.         if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  775.             *cp = '\0';
  776.  
  777.         /* truncate long user names */
  778.         if (strlen(ap->val) > MBOXLEN)
  779.             ap->val[MBOXLEN] = '\0';
  780.  
  781.         /* if mail file is busy save it in our smtp queue
  782.          * and let the smtp daemon try later.
  783.          */
  784.  
  785. #ifdef NOVELL
  786.         if(!novell_start)
  787.         {
  788. #endif
  789.             if (mlock(Mailspool,ap->val))
  790.             {
  791.                 int32 msgid;
  792.  
  793. #if    defined (DEBUG_LOCKS)
  794.                 smtplog ("mailit (): mail spool file %s, %s locked, queueing",
  795.                          Mailspool, ap->val);
  796. #endif
  797.                 addlist(&dlist,ap->val,0);
  798.                 fail = queuejob(data,Hostname,dlist,from,&msgid);
  799.                 if (!fail)
  800.                     delay_job(msgid);
  801.  
  802.                 del_list(dlist);
  803.                 dlist = NULLLIST;
  804.             }
  805. #ifdef NOVELL
  806.         }
  807. #endif
  808.         else
  809.         {
  810.             char buf[LINELEN];
  811.             int tocnt = 0;
  812.             extern int smtpverbose;
  813.  
  814. #ifdef NOVELL
  815.             long int oid;
  816.             char    box[13];
  817.             struct    ffblk    fblock;
  818.             static    int    done_rand=0;
  819.  
  820.             if(novell_start)
  821.             {
  822.                 oid=get_mail_id(ap->val,novell_server_name);
  823.  
  824.                 ltoa(oid,box,16);
  825.  
  826.                 if(!done_rand)
  827.                 {
  828.                     randomize(); /* This is non-deterministic */
  829.                     done_rand=1;
  830.                 }
  831.  
  832.                 do
  833.                 {
  834.                     sprintf(mailbox,"%s/%s/%s/%04x%04x.%s",novell_server_name,"SYS:/MAIL",box,rand(),rand(),novell_mail_ext);
  835.                 }
  836.                 while(!findfirst(mailbox,&fblock,0))
  837.                     ;
  838.             }
  839.             else
  840. #endif
  841.             {
  842.                 sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  843.             }
  844.  
  845. #ifndef    AMIGA
  846.             if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE)
  847.             {
  848. #    ifdef NOVELL
  849.                 if(novell_start)
  850.                 {
  851.                     send_alert(ap->val,novell_server_name,from);
  852.                 }
  853. #    endif
  854.  
  855. #else
  856.             if((fp = fopen(mailbox,"r+")) != NULLFILE)
  857.             {
  858.                 (void) fseek(fp, 0L, 2);
  859. #endif
  860.                 time(&t);
  861.                 if (smtp_separator)
  862.                     fprintf(fp, "%s\n", smtp_separator);
  863.                 fprintf(fp,"From %s %s",from,ctime(&t));
  864.                 host = NULLCHAR;
  865.                 while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  866.                 {
  867.                     if(buf[0] == '\n')
  868.                     {
  869.                         if(tocnt == 0)
  870.                             fprintf(fp,"%s%s\n",
  871.                               Hdrs[APPARTO],
  872.                               ap->val);
  873.                         fputc('\n',fp);
  874.                         break;
  875.                     }
  876.                     fputs(buf,fp);
  877.                     rip(buf);
  878.                     switch(htype(buf))
  879.                     {
  880.                     case TO:
  881.                     case CC:
  882.                         ++tocnt;
  883.                         break;
  884.                     case RRECEIPT:
  885.                         if((cp = getaddress(buf,0))
  886.                           != NULLCHAR)
  887.                         {
  888.                             free(host);
  889.                             host = strdup(cp);
  890.                         }
  891.                         break;
  892.                     }
  893.                 }
  894.                 copy_data(data, fp);
  895.                 if(ferror(fp))
  896.                     fail = 1;
  897.                 else
  898.                     fprintf(fp,"\n");
  899.                 /* Leave a blank line between msgs */
  900.                 fclose(fp);
  901.  
  902.                 if (smtpverbose)
  903.                 {
  904.                     tprintf("New mail arrived for %s from %s\n",ap->val, from);
  905.                 }
  906.  
  907.                 if (Smtpbeep)
  908.                     printf("\a\a");
  909.  
  910.                 if(host != NULLCHAR)
  911.                 {
  912.                     rewind(data); /* Send return receipt */
  913.                     mdaemon(data,host,NULLLIST,0);
  914.                     free(host);
  915.                 }
  916.             }
  917.             else
  918.                 fail = 1;
  919. #ifdef NOVELL
  920.             if(!novell_start)
  921.             {
  922.                 (void) rmlock(Mailspool,ap->val);
  923.             }
  924. #else
  925.             (void) rmlock(Mailspool,ap->val);
  926. #endif
  927.             if (fail)
  928.             {
  929.                 break;
  930.             }
  931.             smtplog("deliver: To: %s From: %s",ap->val,from);
  932.         }
  933.     }
  934.     return fail;
  935. }
  936.  
  937. /* Return Date/Time in Arpanet format in passed string */
  938. char *
  939. ptime(t)
  940. long *t;
  941. {
  942.     /* Print out the time and date field as
  943.      *        "DAY day MONTH year hh:mm:ss ZONE"
  944.      */
  945.     register struct tm *ltm;
  946.     static char tz[4];
  947.     static char str[40];
  948.     char *p;
  949. #ifndef ATARI
  950.      *getenv();
  951. #endif     
  952.     /* Read the system time */
  953.  
  954.     ltm = localtime(t);
  955.  
  956.     if (*tz == '\0') {
  957.         if ((p = getenv("TZ")) == NULL)
  958.             strcpy(tz, "UTC");
  959.         else {
  960.             if (ltm->tm_isdst == 0)
  961.                 strncpy(tz, p, 3);
  962.             else
  963.                 strncpy(tz, p + 4, 3);
  964.         }
  965.     }
  966.  
  967.     /* rfc 822 format */
  968.  
  969.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  970.       Days[ltm->tm_wday],
  971.       ltm->tm_mday,
  972.       Months[ltm->tm_mon],
  973.       ltm->tm_year,
  974.       ltm->tm_hour,
  975.       ltm->tm_min,
  976.       ltm->tm_sec,
  977.       tz);
  978.     return(str);
  979. }
  980.  
  981. long
  982. get_msgid()
  983. {
  984.     char sfilename[LINELEN];
  985.     char s[20];
  986.     register long sequence = 0;
  987.     FILE *sfile;
  988.  
  989.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  990.     sfile = fopen(sfilename,READ_TEXT);
  991.  
  992.     /* if sequence file exists, get the value, otherwise set it */
  993.     if (sfile != NULL)
  994.     {
  995.         (void) fgets(s,sizeof(s),sfile);
  996.         sequence = atol(s);
  997.         /* Keep it in range of and 8 digit number to use for dos name prefix. */
  998.         if (sequence < 0L || sequence > 99999999L )
  999.             sequence = 0;
  1000.         fclose(sfile);
  1001.     }
  1002.  
  1003.     /* increment sequence number, and write to sequence file */
  1004.     sfile = fopen(sfilename,WRITE_TEXT);
  1005.     fprintf(sfile,"%ld",++sequence);
  1006.     fclose(sfile);
  1007.     return sequence;
  1008. }
  1009.  
  1010. #if defined(MSDOS) || defined(ATARI)
  1011. /* Illegal characters in a DOS filename */
  1012. static char baddoschars[] = "\"[]:|<>+=;,";
  1013. #endif
  1014.  
  1015. /* test if mail address is valid */
  1016. int
  1017. validate_address(s)
  1018. char *s;
  1019. {
  1020.     char *cp, *t;
  1021.     int32 addr;
  1022.  
  1023.     /* if address has @ in it the check dest address */
  1024.     if (*s == '@' && (cp = strrchr(s,':')) != NULLCHAR)
  1025.         for (t = s,cp++; (*t++ = *cp++) != 0; )
  1026.             ;
  1027.     if ((cp = strrchr(s,'@')) != NULLCHAR)
  1028.     {
  1029.         cp++;
  1030.         /* 1st check if its our hostname
  1031.         * if not then check the hosts file and see
  1032.         * if we can resolve ther address to a know site
  1033.         * or one of our aliases
  1034.         */
  1035.         if (strcmp(cp,Hostname) != 0)
  1036.         {
  1037.             if ((addr = mailroute(cp, 0)) == 0
  1038.               && (Smtpmode & QUEUE) == 0)
  1039.                 return BADADDR;
  1040.             if (ismyaddr(addr) == NULLIF)
  1041.                 return DOMAIN;
  1042.         }
  1043.  
  1044.         /* on a local address remove the host name part */
  1045.         *--cp = '\0';
  1046.     }
  1047.  
  1048.     /* if using an external router leave address alone */
  1049.     if ((Smtpmode & QUEUE) != 0)
  1050.         return LOCAL;
  1051.  
  1052.     /* check for the user%host hack */
  1053.     if ((cp = strrchr(s,'%')) != NULLCHAR)
  1054.     {
  1055.         *cp = '@';
  1056.         cp++;
  1057.         /* reroute based on host name following the % seperator */
  1058.         if (mailroute(cp, 0) == 0)
  1059.             return BADADDR;
  1060.         else
  1061.             return DOMAIN;
  1062.     }
  1063.  
  1064. #if defined (MSDOS) || defined(ATARI)    /* dos file name checks */
  1065.     /* Check for characters illegal in MS-DOS file names */
  1066.     for(cp = baddoschars;*cp != '\0';cp++)
  1067.     {
  1068.         if(strchr(s,*cp) != NULLCHAR)
  1069.             return BADADDR;    
  1070.     }
  1071. #endif
  1072.     return LOCAL;
  1073. }
  1074.  
  1075. /* place a mail job in the outbound queue */
  1076. int
  1077. queuejob(dfile,host,to,from,msgid)
  1078. FILE *dfile;
  1079. char *host;
  1080. struct list *to;
  1081. char *from;
  1082. int32 *msgid;
  1083. {
  1084.     FILE *fp;
  1085.     struct list *ap;
  1086.     char tmpstring[50], prefix[9], buf[LINELEN];
  1087.     register int cnt;
  1088.     int32 this_msgid;
  1089.  
  1090.     this_msgid = get_msgid();
  1091.     sprintf(prefix,"%ld",this_msgid);
  1092.     if (msgid)
  1093.         *msgid = this_msgid;
  1094.     mlock(Mailqdir,prefix);
  1095.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  1096.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1097.     {
  1098.         (void) rmlock(Mailqdir,prefix);
  1099.         return 1;
  1100.     }
  1101.     while((cnt = fread(buf, 1, LINELEN, dfile)) > 0)
  1102.         if(fwrite(buf, 1, cnt, fp) != cnt)
  1103.             break;
  1104.     if(ferror(fp))
  1105.     {
  1106.         fclose(fp);
  1107.         (void) rmlock(Mailqdir,prefix);
  1108.         return 1;
  1109.     }
  1110.     fclose(fp);
  1111.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  1112.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1113.     {
  1114.         (void) rmlock(Mailqdir,prefix);
  1115.         return 1;
  1116.     }
  1117.     fprintf(fp,"%s\n%s\n",host,from);
  1118.     for(ap = to; ap != NULLLIST; ap = ap->next)
  1119.     {
  1120.         fprintf(fp,"%s\n",ap->val);
  1121.         smtplog("queue job %s To: %s From: %s",prefix,ap->val,from);
  1122.     }
  1123.     fclose(fp);
  1124.     (void) rmlock(Mailqdir,prefix);
  1125.     return 0;
  1126. }
  1127.  
  1128. /* Deliver mail to the appropriate mail boxes */
  1129. static int
  1130. router_queue(data,from,to)
  1131. FILE *data;
  1132. char *from;
  1133. struct list *to;
  1134. {
  1135.     register struct list *ap;
  1136.     FILE *fp;
  1137.     char tmpstring[50];
  1138.     char prefix[9];
  1139.  
  1140.     sprintf(prefix,"%ld",get_msgid());
  1141.     mlock(Routeqdir,prefix);
  1142.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  1143.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1144.     {
  1145.         (void) rmlock(Routeqdir,prefix);
  1146.         return 1;
  1147.     }
  1148.     rewind(data);
  1149.     copy_data(data, fp);
  1150.     if(ferror(fp))
  1151.     {
  1152.         fclose(fp);
  1153.         (void) rmlock(Routeqdir,prefix);
  1154.         return 1;
  1155.     }
  1156.     fclose(fp);
  1157.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  1158.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE)
  1159.     {
  1160.         (void) rmlock(Routeqdir,prefix);
  1161.         return 1;
  1162.     }
  1163.     fprintf(fp,"From: %s\n",from);
  1164.     for(ap = to;ap != NULLLIST;ap = ap->next)
  1165.     {
  1166.         fprintf(fp,"To: %s\n",ap->val);
  1167.     }
  1168.     fclose(fp);
  1169.     (void) rmlock(Routeqdir,prefix);
  1170.     smtplog("rqueue job %s From: %s",prefix,from);
  1171.     return 0;
  1172. }
  1173.  
  1174. /* add an element to the front of the list pointed to by head
  1175. ** return NULLLIST if out of memory.
  1176. */
  1177. struct list *
  1178. addlist(head,val,type)
  1179. struct list **head;
  1180. char *val;
  1181. int type;
  1182. {
  1183.     register struct list *tp;
  1184.  
  1185.     tp = (struct list *)callocw(1,sizeof(struct list));
  1186.  
  1187.     tp->next = NULLLIST;
  1188.  
  1189.     /* allocate storage for the char string */
  1190.     tp->val = strdup(val);
  1191.     tp->type = type;
  1192.  
  1193.     /* add entry to front of existing list */
  1194.     if (*head == NULLLIST)
  1195.         *head = tp;
  1196.     else
  1197.     {
  1198.         tp->next = *head;
  1199.         *head = tp;
  1200.     }
  1201.     return tp;
  1202.  
  1203. }
  1204.  
  1205. /* Remove and entry from the list ...            CMS 19/12/92
  1206.     return TRUE on success or FALSE on failure */
  1207. static int remlist(struct list **head, struct list *unwanted)
  1208.     {
  1209.     struct list *ptr, **prev;
  1210.     prev = head;
  1211.     for (ptr = *head; ptr; ptr = ptr->next)
  1212.         if (ptr == unwanted)
  1213.             {
  1214.             *prev = ptr->next;
  1215.             free (ptr);
  1216.             break;
  1217.             }
  1218.         else prev = &ptr->next;
  1219.     return ptr == unwanted;
  1220.     }
  1221.  
  1222. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  1223. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  1224.  
  1225. /* check for and alias and expand alias into a address list */
  1226. static struct list *
  1227. expandalias(head, user)
  1228. struct list **head;
  1229. char *user;
  1230. {
  1231.     FILE *fp;
  1232.     register char *s,*p;
  1233.     struct rr *rrp, *rrlp;
  1234.     int inalias = 0;
  1235.     struct list *tp;
  1236.     char buf[LINELEN];
  1237.  
  1238.     /* no alias file found */
  1239.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE)
  1240.     {
  1241.         fail = FAIL_DELIVER;
  1242.         /* Try MB, MG or MR domain name records */
  1243.         rrlp = rrp = resolve_mailb(user);
  1244.         while(rrp != NULLRR)
  1245.         {
  1246.             if(rrp->rdlength > 0)
  1247.             {
  1248.                 /* remove the trailing dot */
  1249.                 rrp->rdata.name[rrp->rdlength-1] = '\0';
  1250.                 /* replace first dot with @ if there is no @ */
  1251.                 if(strchr(rrp->rdata.name,'@') == NULLCHAR
  1252.                   && (p = strchr(rrp->rdata.name,'.')) !=
  1253.                   NULLCHAR)
  1254.                     *p = '@';
  1255.                 if(strchr(rrp->rdata.name,'@') != NULLCHAR)
  1256.                     tp = addlist(head,rrp->rdata.name,
  1257.                       DOMAIN);
  1258.                 else
  1259.                     tp = addlist(head,rrp->rdata.name,
  1260.                       LOCAL);
  1261.                 ++inalias;
  1262.             }
  1263.             rrp = rrp->next;
  1264.         }
  1265.         free_rr(rrlp);
  1266.         if(inalias)
  1267.             return tp;
  1268.         else
  1269.             return addlist(head, user, LOCAL);
  1270.     }
  1271.  
  1272.     while (fgets(buf,LINELEN,fp) != NULLCHAR)
  1273.     {
  1274.         p = buf;
  1275.         if ( *p == '#' || *p == '\0')
  1276.             continue;
  1277.         rip(p);
  1278.  
  1279.         /* if not in an matching entry skip continuation lines */
  1280.         if (!inalias && isspace(*p))
  1281.             continue;
  1282.  
  1283.         /* when processing an active alias check for a continuation */
  1284.         if (inalias)
  1285.         {
  1286.             if (!isspace(*p))
  1287.                 break;    /* done */
  1288.         }
  1289.         else
  1290.         {
  1291.             s = p;
  1292.             SKIPWORD(p);
  1293.             *p++ = '\0';    /* end the alias name */
  1294.             SKIPSPACE (p);
  1295.             if (fail == NO_FAIL && strcmp(s, "default") == 0)
  1296.                 if (strncmp(p, "deliver", 3) == 0)
  1297.                     fail = FAIL_DELIVER;
  1298.                 else {
  1299.                     fail = FAIL_DEFAULT;
  1300.                     strcpy(default_address, p);
  1301.                     }
  1302.             if (strcmp(s,user) != 0)
  1303.                 continue;    /* no match go on */
  1304.             inalias = 1;
  1305.         }
  1306.  
  1307.         /* process the recipients on the alias line */
  1308.         SKIPSPACE(p);
  1309.         while(*p != '\0' && *p != '#')
  1310.         {
  1311.             s = p;
  1312.             SKIPWORD(p);
  1313.             if (*p != '\0')
  1314.                 *p++ = '\0';
  1315.  
  1316.             /* find hostname */
  1317.             if (strchr(s,'@') != NULLCHAR)
  1318.                 tp = addlist(head,s,DOMAIN);
  1319.             else
  1320.                 tp = addlist(head,s,LOCAL);
  1321.             SKIPSPACE(p);
  1322.         }
  1323.     }
  1324.     (void) fclose(fp);
  1325.  
  1326.     if (inalias)    /* found and processed and alias. */
  1327.         return tp;
  1328.  
  1329.     /* no alias found treat as a local address */
  1330.     return addlist(head, user, LOCAL);
  1331. }
  1332.  
  1333. #if    defined(ANSIPROTO)
  1334. static void
  1335. smtplog(char *fmt, ...)
  1336. {
  1337.     va_list ap;
  1338.     char *cp;
  1339.     long t;
  1340.     FILE *fp;
  1341.  
  1342.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1343.         return;
  1344.     time(&t);
  1345.     cp = ctime(&t);
  1346.     rip(cp);
  1347.     fprintf(fp,"%s ",cp);
  1348.     va_start(ap,fmt);
  1349.     vfprintf(fp,fmt,ap);
  1350.     va_end(ap);
  1351.     fprintf(fp,"\n");
  1352.     fclose(fp);
  1353. }
  1354.  
  1355. #else
  1356.  
  1357. static void
  1358. smtplog(fmt,arg1,arg2,arg3,arg4)
  1359. char *fmt;
  1360. int arg1,arg2,arg3,arg4;
  1361. {
  1362.     char *cp;
  1363.     long t;
  1364.     FILE *fp;
  1365.  
  1366.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  1367.         return;
  1368.     time(&t);
  1369.     cp = ctime(&t);
  1370.     rip(cp);
  1371.     fprintf(fp,"%s ",cp);
  1372.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  1373.     fprintf(fp,"\n");
  1374.     fclose(fp);
  1375. }
  1376. #endif
  1377.  
  1378. /* send mail to a single user. Can be called from the ax24 mailbox or
  1379. ** from the return mail function in the smtp client
  1380. */
  1381. static int
  1382. mailuser(data,from,to)
  1383. FILE *data;
  1384. char *from;
  1385. char *to;
  1386. {
  1387.  
  1388.     int address_type, ret;
  1389.     struct list *tolist = NULLLIST;
  1390.  
  1391.     /* check if address is ok */
  1392.     if ((address_type = validate_address(to)) == BADADDR)
  1393.     {
  1394.         return 1;
  1395.     }
  1396.     /* if a local address check for an alias */
  1397.     if (address_type == LOCAL)
  1398.         expandalias(&tolist, to);
  1399.     else
  1400.         /* a remote address is added to the list */
  1401.         addlist(&tolist, to, address_type);
  1402.     ret = mailit(data,from,tolist);
  1403.     del_list(tolist);
  1404.     return ret;
  1405.  
  1406. }
  1407.  
  1408. /* Mailer daemon return mail mechanism */
  1409. int
  1410. mdaemon(data,to,lp,bounce)
  1411. FILE *data;        /* pointer to rewound data file */
  1412. char *to;        /* Overridden by Errors-To: line if bounce is true */
  1413. struct list *lp;    /* error log for failed mail */
  1414. int bounce;        /* True for failed mail, otherwise return receipt */
  1415. {
  1416.     time_t t;
  1417.     FILE *tfile;
  1418.     char buf[LINELEN], *cp, *newto = NULLCHAR;
  1419.     int cnt;
  1420.     if(to == NULLCHAR || (to != NULLCHAR && *to == '\0') || bounce)
  1421.     {
  1422.         while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  1423.         {
  1424.             if(buf[0] == '\n')
  1425.                 break;
  1426.             /* Look for Errors-To: */
  1427.             if(htype(buf) == ERRORSTO &&
  1428.               (cp = getaddress(buf,0)) != NULLCHAR)
  1429.             {
  1430.                 free(newto);
  1431.                 newto = strdup(cp);
  1432.                 break;
  1433.             }
  1434.         }
  1435.         if(newto == NULLCHAR && ((to != NULLCHAR && *to == '\0') ||
  1436.           to == NULLCHAR))
  1437.             return -1;
  1438.         rewind(data);
  1439.     }
  1440.     if((tfile = tmpfile()) == NULLFILE)
  1441.         return -1;
  1442.     time(&t);
  1443.     fprintf(tfile,"%s%s",Hdrs[DATE],ptime(&t));
  1444.     fprintf(tfile,"%s<%ld@%s>\n",Hdrs[MSGID],get_msgid(),Hostname);
  1445.     fprintf(tfile,"%sMAILER-DAEMON@%s (Mail Delivery Subsystem)\n",
  1446.       Hdrs[FROM],Hostname);
  1447.     fprintf(tfile,"%s%s\n",Hdrs[TO],newto != NULLCHAR ? newto : to);
  1448.     fprintf(tfile,"%s%s\n\n",Hdrs[SUBJECT],
  1449.       bounce ? "Failed mail" : "Return receipt");
  1450.     if(bounce)
  1451.     {
  1452.         fprintf(tfile,"  ===== transcript follows =====\n\n");
  1453.         for (; lp != NULLLIST; lp = lp->next)
  1454.             fprintf(tfile,"%s\n",lp->val);
  1455.         fprintf(tfile,"\n");
  1456.     }
  1457.     fprintf(tfile,"  ===== %s follows ====\n",
  1458.       bounce ? "Unsent message" : "Message header");
  1459.  
  1460.     while(fgets(buf,sizeof(buf),data) != NULLCHAR)
  1461.     {
  1462.         if(buf[0] == '\n')
  1463.             break;
  1464.         fputs(buf,tfile);
  1465.     }
  1466.     if(bounce)
  1467.     {
  1468.         fputc('\n',tfile);
  1469.         while((cnt = fread(buf,1,sizeof(buf),data)) > 0)
  1470.             fwrite(buf,1,cnt,tfile);
  1471.     }
  1472.     fseek(tfile,0L,0);
  1473.  
  1474.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  1475.  
  1476.     sprintf(buf, "postmaster@%s", Hostname);
  1477.     mailuser(tfile, buf, newto != NULLCHAR ? newto : to);
  1478.  
  1479.     fclose(tfile);
  1480.     free(newto);
  1481.     return 0;
  1482. }
  1483.  
  1484. /* Check to see that we are accepting mail from this sender. If we aren't
  1485.  * then tell 'em that mail from them is Unwanted. I added this facility to
  1486.  * allow auto-rejection of messages from auto-reply daemons. G7LEU
  1487.  */
  1488. static int
  1489. validate_sender(sender)
  1490. char *sender;
  1491. {
  1492.     FILE *fp;
  1493.     char buf[LINELEN + 1], *p;
  1494.     if ((fp = fopen(Mailkill, READ_TEXT)) == NULLFILE)
  1495.         /* Can't open SMTP reject file so let 'em through */
  1496.         return 1;
  1497.     while (fgets(buf,LINELEN,fp) != NULLCHAR)
  1498.         {
  1499.         p = buf;
  1500.         if (*p == '#' || *p == '\0')
  1501.             continue;
  1502.         rip(p);
  1503.         if (!stricmp(p, sender))
  1504.             {
  1505.             extern int smtpverbose;
  1506.             if (smtpverbose)
  1507.                 tprintf("SMTP: Rejected mail from '%s'\n", sender);
  1508.             fclose(fp);
  1509.             return 0;
  1510.             }
  1511.         }
  1512.     fclose(fp);
  1513.     /* Sender OK */
  1514.     return 1;
  1515. }
  1516.  
  1517.  
  1518. /* Check to see if a local user actually exists - use the FTPUSERS file
  1519.  * Returns 0 if the user doesn't exist, 1 otherwise
  1520.  */
  1521. static int
  1522. validate_user(user)
  1523. char *user;
  1524. {
  1525.     char *cp;
  1526.  
  1527. /* always allow 'postmaster' */
  1528.     if (stricmp(user,"postmaster")==0)
  1529.     {
  1530.         return 1;
  1531.     }
  1532. /* otherwise check the ftpusers file */
  1533.  
  1534. #    ifdef NOVELL
  1535.     if(novell_start)
  1536.     {
  1537.         if(!get_mail_id(user,novell_server_name))
  1538.         {
  1539.             return    0;
  1540.         }
  1541.     }
  1542.     else
  1543. #    endif
  1544.     {
  1545.         if ((cp=userlookup(user,NULL,NULLCHARP,NULLINT,NULL)) == NULLCHAR)
  1546.         {
  1547.             return 0;
  1548.         }
  1549.         free(cp);
  1550.     }
  1551.     return 1;
  1552. }
  1553.